package agents.task;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import agents.Ant;
import agents.resource.ResourceAgent;
import agents.resource.exceptions.BookingFailedException;
import domain.Car;
import domain.Clock;
import domain.TimeInterval;

public class IntentionAnt implements Ant {

	public IntentionAnt(Trip tripToBook, TaskAgent origin) {
		this.origin = origin;
		this.tripIterator = tripToBook.iterator();
		this.currentLocation = getOrigin().getCurrentResource();
		this.locationEnterTime = -1;
	}
	
	//gaat resources in meegegeven trip af en boekt deze
	//als boektijd bezet is in resource, boekt zo vroeg mogelijk
	//keert daarna terug naar task agent en verwittigt deze van zijn terugkomst
	public void doStep() {
		Car carToBook = getOrigin().getCar();
		
		if(tripIterator.hasNext()) {
			TripStep nextTripStep = tripIterator.next();
			long startBooking = locationEnterTime;
			long endBooking = nextTripStep.getEnterTime() - 1;
			
			if(startBooking == -1) { //als we op huidige postie van de auto zitten, boek exit time
				endBooking = Math.max(endBooking, currentLocation.getFirstExitTimeOf(carToBook));
				if(endBooking >= Clock.getInstance().getCurrentTime()) { //boeking niet nodig als we op dit moment de resource gaan verlaten
					try {
						currentLocation.bookExitResource(endBooking, carToBook);
					} catch(BookingFailedException b) {
						throw new RuntimeException("unexpected failed booking", b);
					}
				}
			} else { //anders boek heel interval voor de resource
				List<TimeInterval> freeIntervals = currentLocation.getFreeIntervals(startBooking, carToBook);
				
				int i = 0;
				boolean possibleInterval = false;
				
				while (!possibleInterval){
					startBooking = freeIntervals.get(i).getStartTime();
					TimeInterval possibleExitInterval = currentLocation.getPossibleExitInterval(startBooking, carToBook);
					if(possibleExitInterval != null) {
						if(!possibleExitInterval.contains(endBooking)) { //boeken tot zo dicht mogelijk bij gepland verlaten van resource
							if(possibleExitInterval.getStartTime() > endBooking) {
								endBooking  = possibleExitInterval.getStartTime();
							} else
								endBooking  = possibleExitInterval.getEndTime();
						}
						possibleInterval = true;
					} else
						i++;
				}
	
				TimeInterval intervalToBook = new TimeInterval(startBooking, endBooking);
				try {
					currentLocation.book(intervalToBook, origin.getCar());
					bookedTrip.append(new TripStep(currentLocation,startBooking));
				} catch(BookingFailedException b) {
					//shouldn't happen
					throw new RuntimeException("unexpected failed booking",b);
				}
			}
			currentLocation = nextTripStep.getResourceAgent();
			locationEnterTime = endBooking+1;
		} else {
			origin.notifyIntentionAntArrival(this);
			terminate();
		}
	}
	
	//geeft uiteindelijk geboekte trip terug, null indien een trafficinfrastructure niet meer bestaat (wegenwerken)
	public Trip getBookedTrip() {
		return bookedTrip; 
	}

	public List<Ant> getChildAnts() {
		return new ArrayList<Ant>();
	}

	public boolean isTerminated() {
		return isTerminated;
	}
	protected void terminate() {
		isTerminated = true;
	}
	
	protected TaskAgent getOrigin() {
		return origin;
	}
	
	@Override
	public String toString(){
		return "location: "+currentLocation.toString()+", origin: " + getOrigin().toString();
	}
	
	//huidige positie van de ant
	private ResourceAgent currentLocation;
	private long locationEnterTime;
	private Trip bookedTrip = new Trip();
	private final Iterator<TripStep> tripIterator;
	private boolean isTerminated = false;
	private final TaskAgent origin;
}
